package com.hjh.testdemo.ui.usb.host

import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbEndpoint
import android.hardware.usb.UsbInterface
import android.hardware.usb.UsbManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable.isActive
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.coroutines.coroutineContext

/**
 * @author： hjh
 * @createDate： 2025/6/17 11:40
 * @description：
 * @qq： 3472903821
 * @version: 1.0
 */
class UsbDeviceCommunicator(
    private val usbManager: UsbManager,
    private val device: UsbDevice,
    private val onReceive: (String) -> Unit,
    private val onError: (String) -> Unit,
    private val onSend: (String) -> Unit
) {

    private var connection: UsbDeviceConnection? = null
    private var usbInterface: UsbInterface? = null
    private var endpointIn: UsbEndpoint? = null
    private var endpointOut: UsbEndpoint? = null
    private var readJob: Job? = null

    fun connect(): Boolean {
        for (i in 0 until device.interfaceCount) {
            val iface = device.getInterface(i)
            if (iface.endpointCount >= 2) {
                var inEndpoint: UsbEndpoint? = null
                var outEndpoint: UsbEndpoint? = null
                for (j in 0 until iface.endpointCount) {
                    val endpoint = iface.getEndpoint(j)
                    if (endpoint.type == UsbConstants.USB_ENDPOINT_XFER_BULK) {
                        if (endpoint.direction == UsbConstants.USB_DIR_IN) inEndpoint = endpoint
                        else outEndpoint = endpoint
                    }
                }
                if (inEndpoint != null && outEndpoint != null) {
                    usbInterface = iface
                    endpointIn = inEndpoint
                    endpointOut = outEndpoint
                    break
                }
            }
        }

        val iface = usbInterface ?: return false
        connection = usbManager.openDevice(device)?.apply {
            if (!claimInterface(iface, true)) return false
        }
        readJob = CoroutineScope(Dispatchers.IO).launch { readLoop() }
        return true
    }

    fun send(message: String) {
        val bytes = message.toByteArray()
        val result = connection?.bulkTransfer(endpointOut, bytes, bytes.size, 1000)
        if (result != null && result > 0) onSend(message) else onError("发送失败")
    }

    private suspend fun readLoop() {
        val buffer = ByteArray(64)
        while (coroutineContext.isActive) {
            val size = connection?.bulkTransfer(endpointIn, buffer, buffer.size, 1000) ?: -1
            if (size > 0) {
                val msg = String(buffer, 0, size)
                withContext(Dispatchers.Main) { onReceive(msg) }
            }
        }
    }

    fun disconnect() {
        readJob?.cancel()
        connection?.releaseInterface(usbInterface)
        connection?.close()
    }
}